﻿/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkUtil.h"
#include "MkLog.h"
#include "MkBase64.h"
#include "MkCoreConfig.h"
#include <time.h>
#include <string.h>

#ifdef _WIN32
#include <WS2tcpip.h>
#include <WSPiApi.h>
#include <tchar.h>
#include <Psapi.h>
#include <tlhelp32.h>
#include <io.h>
#include <process.h>
#include <regex>
#else
#include <netdb.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <regex.h>
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <iconv.h>
#endif


#define MAX_RANDOM_COUNT  62

static Int8 g_pcRandom[MAX_RANDOM_COUNT] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
                                             'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
                                             'W', 'X', 'Y', 'Z'
};
const Int8 pHex[Len16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
const Int8 pLowHex[Len16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

MkString CMkUtil::m_EmptyString;
Uint32 CMkUtil::GetVersion(MkString& Version)
{
    Version = VERSION + MkString("_build(") + __DATE__ + MkString(" ") + __TIME__ + ")";
    return NoneError;
}

Uint32 CMkUtil::GetRandomNumber()
{
    static Uint32 tmp = 0;
    tmp += static_cast<Uint32>(time(nullptr));
    srand(tmp);
    return static_cast<Uint32>(rand());
}

MkString& CMkUtil::CreateRandomString(int nLen, MkString &Str)
{
    static Uint32 tmp = 0;
    tmp += static_cast<Uint32>(time(nullptr));
    srand(tmp);
    Str.clear();
    for (int i = 0; i < nLen; i++) {
        Str += g_pcRandom[rand() % MAX_RANDOM_COUNT];
    }
    return Str;
}

BOOL CMkUtil::CheckValidHttpUrl(const MkString &HttpUrl)
{
    const char *strRegex = "(https?)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]";
#ifdef _WIN32
    return (1 == std::regex_match(HttpUrl, std::regex(strRegex)));
#else
    regex_t reg;
    int flag = REG_EXTENDED;
    regcomp(&reg, strRegex, flag);
    regmatch_t pmatch[1];
    const size_t nmatch = 1;
    int status = regexec(&reg, HttpUrl.c_str(), nmatch, pmatch, 0);
    regfree(&reg);
    return 0 == status;
#endif
}

BOOL CMkUtil::CheckVaildRtspUrl(const MkString &RtspUrl)
{
    const char *strRegex = "(rtsp)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]";
    BOOL bRet = FALSE;
#ifdef _WIN32
    bRet = (1 == std::regex_match(RtspUrl, std::regex(strRegex)));
#else
    regex_t reg;
    int flag = REG_EXTENDED;
    regcomp(&reg, strRegex, flag);
    regmatch_t pmatch[1];
    const size_t nmatch = 1;
    int status = regexec(&reg, RtspUrl.c_str(), nmatch, pmatch, 0);
    regfree(&reg);
    bRet = 0 == status;
#endif
    return bRet;
}

BOOL CMkUtil::CheckVaildRtmpUrl(const MkString &RtmpUrl)
{
    const char *strRegex = "(rtmp)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]";
#ifdef _WIN32
    return (1 == std::regex_match(RtmpUrl, std::regex(strRegex)));
#else
    regex_t reg;
    int flag = REG_EXTENDED;
    regcomp(&reg, strRegex, flag);
    regmatch_t pmatch[1];
    const size_t nmatch = 1;
    int status = regexec(&reg, RtmpUrl.c_str(), nmatch, pmatch, 0);
    regfree(&reg);
    return 0 == status;
#endif
}

BOOL CMkUtil::CheckValidIp(const MkString& Ip)
{
    const char *strRegex = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}";
#ifdef _WIN32
    return (1 == std::regex_match(Ip, std::regex(strRegex)));
#else
    regex_t reg;
    int flag = REG_EXTENDED;
    regcomp(&reg, strRegex, flag);
    regmatch_t pmatch[1];
    const size_t nmatch = 1;
    int status = regexec(&reg, Ip.c_str(), nmatch, pmatch, 0);
    regfree(&reg);
    return 0 == status;
#endif
}

Uint32 CMkUtil::GetMkHttpUrl(const MkString &HttpUrl, MkString &MkHttpUrl)
{
    char cEnd = HttpUrl.at(HttpUrl.size() - 1);
    if (cEnd == '/'
        || cEnd == '\\') {
        MkHttpUrl = HttpUrl.substr(0, HttpUrl.size() - 1);
    } else {
        MkHttpUrl = HttpUrl;
    }

    return NoneError;
}

Uint32 CMkUtil::GetSystemCpuThreadNum(Uint32 &CpuThreadNum)
{
#ifdef _WIN32
    SYSTEM_INFO sysInfo;
    GetSystemInfo(&sysInfo);
    CpuThreadNum = sysInfo.dwNumberOfProcessors;
#else
    long cpu_num;
    cpu_num = sysconf(_SC_NPROCESSORS_CONF);
    //printf("_SC_NPROCESSORS_CONF=%d\n", cpu_num);

    cpu_num = sysconf(_SC_NPROCESSORS_ONLN);
    //printf("_SC_NPROCESSORS_ONLN=%d\n", cpu_num);
    CpuThreadNum = static_cast<Uint32>(cpu_num);
#endif // _WIN32
    return NoneError;
}

SOCKET CMkUtil::CreateListenSocket(Uint16 Port, BOOL IsTcp/* = TRUE*/, const MkString& Host/* = ""*/)
{
    int ret = 0;
    socklen_t addrlen = sizeof(struct sockaddr);
    SOCKET sock = -1;
    sock = socket(AF_INET, IsTcp ? SOCK_STREAM : SOCK_DGRAM, 0);
    if (-1 == sock) {
        MkErrorLog("create socket failed\n");
        return -1;
    }

    long size = 1024 * 1024 * 20;
#ifdef _WIN32
    setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)(&size), sizeof(size));
    setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)(&size), sizeof(size));
#else
    setsockopt(sock, SOL_SOCKET, SO_SNDBUF, static_cast<void *>(&size), sizeof(size));
    setsockopt(sock, SOL_SOCKET, SO_RCVBUF, static_cast<void *>(&size), sizeof(size));
#endif

    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(Port);
    if (Host.empty()) {
        local.sin_addr.s_addr = 0;
    } else {
        local.sin_addr.s_addr = inet_addr(Host.c_str());
    }


    ret = bind(sock, (struct sockaddr *)&local, addrlen);
    if (-1 == ret) {
        MkErrorLog("bind socket failed\n");
        closesocket(sock);
        return -1;
    }
    if (IsTcp) {
        listen(sock, 5);
    }
    return sock;
}

SOCKET CMkUtil::CreateClientSocket(const MkString &Host, Uint16 Port, int WaitTime)
{
    int ret = 0;
    socklen_t addrlen = sizeof(struct sockaddr);
    SOCKET sock = -1;
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sock) {
        MkErrorLog("create socket failed\n");
        return -1;
    }
    struct sockaddr_in RemoteAddr;
    RemoteAddr.sin_family = AF_INET;
    RemoteAddr.sin_port = htons(Port);
    RemoteAddr.sin_addr.s_addr = inet_addr(Host.c_str());
    struct timeval timeout;
    timeout.tv_sec = WaitTime / 1000;
    timeout.tv_usec = (WaitTime % 1000) * 1000;
    long size = 1024 * 1024 * 20;
#ifdef _WIN32
    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)(&timeout), sizeof(struct timeval));
    setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)(&timeout), sizeof(struct timeval));
    setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)(&size), sizeof(size));
    setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)(&size), sizeof(size));
#else
    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, static_cast<void *>(&timeout), sizeof(struct timeval));
    setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, static_cast<void *>(&timeout), sizeof(struct timeval));
    setsockopt(sock, SOL_SOCKET, SO_SNDBUF, static_cast<void *>(&size), sizeof(size));
    setsockopt(sock, SOL_SOCKET, SO_RCVBUF, static_cast<void *>(&size), sizeof(size));
#endif

#ifdef _WIN32
    unsigned long on = 1;
    if (ioctlsocket(sock, FIONBIO, &on) < 0) {
        MkErrorLog("ioctlsocket(%s:%d) failed\n", Host.c_str(), Port);
        shutdown(sock, 1);
        closesocket(sock);
        return -1;
    }
#else
    int flags;
    if ((flags = fcntl(sock, F_GETFL, nullptr)) < 0
        || fcntl(sock, F_SETFL, flags | O_NONBLOCK)) {
        shutdown(sock, 1);
        closesocket(sock);
        return -1;
    }
#endif

    ret = connect(sock, (struct sockaddr *)&RemoteAddr, addrlen);
    if (ret < 0) {
        socklen_t len = sizeof(int);
        int error = 0;
        getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&error, &len);
        fd_set writeset;
        fd_set readSet;
        fd_set errSet;
        FD_ZERO(&writeset);
        FD_ZERO(&readSet);
        FD_ZERO(&errSet);
        FD_SET(sock, &writeset);
        FD_SET(sock, &readSet);
        FD_SET(sock, &errSet);
        ret = select(sock + 1, &readSet, &writeset, &errSet, &timeout);
        if (FD_ISSET(sock, &errSet)
            || ret <= 0) {
            MkErrorLog("connect(%s:%d) timeout\n", Host.c_str(), Port);
            shutdown(sock, 1);
            closesocket(sock);
            return -1;
        } else if (FD_ISSET(sock, &readSet)) {
            char pbuf[2] = { 0 };
            ret = recv(sock, pbuf, 2, 0);
            if (ret <= 0) {
                MkErrorLog("connect(%s:%d) timeout\n", Host.c_str(), Port);
                shutdown(sock, 1);
                closesocket(sock);
                return -1;
            }
        }
        return sock;
    }
    return sock;
}

Uint32 CMkUtil::CheckHttpUrlConnectAbled(const MkString &HttpUrl)
{
    MkString Host;
    Uint16 Port;
    MkString Path;
    Uint32 ErrorCode = HttpUrlParse(HttpUrl, Host, Port, Path);
    MkCheckErrorLog(ErrorCode, "http url:%s parse failed\n", HttpUrl.c_str());
    return CheckHostPortConnectAbled(Host, Port);
}

Uint32 CMkUtil::CheckHostPortConnectAbled(const MkString &Host, Uint16 Port)
{
    SOCKET fd = CreateClientSocket(Host, Port, 3000);
    if (INVALID_SOCKET != fd) {
#ifdef _WIN32
        closesocket(fd);
#else
        close(fd);
#endif
        return NoneError;
    }
    return SocketConnectFailed;
}

Uint32 CMkUtil::GetLocalThreadId()
{
#ifdef _WIN32
    return GetCurrentThreadId();
#else
    return static_cast<Uint32>(pthread_self());
#endif
}

Uint32 CMkUtil::CheckUdpIsUseAbled(Uint16 Port, const MkString& Host/* = ""*/)
{
    SOCKET Sock = CreateListenSocket(Port, FALSE, Host);
    if (INVALID_SOCKET == Sock) {
        return SocketListenFailed;
    }
    closesocket(Sock);
    return NoneError;
}

Uint32 CMkUtil::CheckTcpIsUseAbled(Uint16 Port, const MkString& Host/* = ""*/)
{
    SOCKET Sock = CreateListenSocket(Port, TRUE, Host);
    if (INVALID_SOCKET == Sock) {
        return SocketListenFailed;
    }
    closesocket(Sock);
    return NoneError;
}

Uint32 CMkUtil::GetFreeTcpPort(Uint16 BeginPort, Uint16 EndPort, Uint16 CurPort, Uint16& FreePort)
{
    Uint32 ErrorCode = SocketListenFailed;
    for (Uint16 i = CurPort; i < EndPort; i++) {
        if (NoneError == CheckTcpIsUseAbled(i)) {
            FreePort = i;
            return NoneError;
        }
    }

    for (Uint16 i = BeginPort; i < CurPort; i++) {
        if (NoneError == CheckTcpIsUseAbled(i)) {
            FreePort = i;
            ErrorCode = NoneError;
            break;
        }
    }
    return ErrorCode;
}

Uint32 CMkUtil::GetFreeUdpPort(Uint16 BeginPort, Uint16 EndPort, Uint16 CurPort, Uint16& FreePort)
{
    Uint32 ErrorCode = SocketListenFailed;
    for (Uint16 i = CurPort; i < EndPort; i += 2) {
        if (NoneError == CheckUdpIsUseAbled(i)) {
            FreePort = i;
            return NoneError;
        }
    }

    for (Uint16 i = BeginPort; i < CurPort; i += 2) {
        if (NoneError == CheckUdpIsUseAbled(i)) {
            FreePort = i;
            ErrorCode = NoneError;
            break;
        }
    }
    return ErrorCode;
}

Uint32 CMkUtil::ByteToString(const Uint8 *pcStr, Uint32 nLen, MkString &str, BOOL bLowLetters/* = FALSE*/)
{
    const Int8* pLetHex = bLowLetters ? pLowHex : pHex;
    for (Uint32 i = 0; i < nLen; i++) {
        str += pLetHex[pcStr[i] >> 4];
        str += pLetHex[pcStr[i] & 0x0f];
    }
    return NoneError;
}

Uint8 CMkUtil::ByteToChar(Uint8 ucByte)
{
    if (ucByte >= '0' && ucByte <= '9') {
        return ucByte - '0';
    } else if (ucByte >= 'A' && ucByte <= 'F') {
        return 10 + ucByte - 'A';
    } else if (ucByte >= 'a' && ucByte <= 'f') {
        return 10 + ucByte - 'a';
    }
    return 0;
}

Uint32 CMkUtil::StringToByte(const MkString &str, Uint8 *pcStr, Uint32 &nLen)
{
    size_t byteSize = str.size();
    Uint8 ptmp = 0;
    size_t i = 0;
    size_t Index = 0;
    if (byteSize % 2) {
        pcStr[0] = ByteToChar(static_cast<Uint8>(str[0]));
        Index = 1;
    }
    for (i = 0; i < byteSize / 2; i++) {
        ptmp = ByteToChar(static_cast<Uint8>(str[2 * i]));
        ptmp = static_cast<Uint8>(ptmp << 4);
        ptmp += ByteToChar(static_cast<Uint8>(str[2 * i + 1]));
        pcStr[Index + i] = ptmp;
    }
    nLen = static_cast<Uint32>(i + Index);
    return NoneError;
}

MkString& CMkUtil::Replace(MkString &str, const MkString &before, const MkString &after)
{
    for (MkString::size_type pos(0); pos != MkString::npos; pos += after.length()) {
        pos = str.find(before, pos);
        if (pos != MkString::npos)
            str.replace(pos, before.length(), after);
        else
            break;
    }
    return str;
}

Uint32 CMkUtil::StringSplit(const MkString &Src, const MkString &SplitStr, MkVectorString &VesDst)
{
    MkString strResult;
    MkString strLeave = Src;
    size_t nFind;
    while (TRUE) {
        nFind = strLeave.find(SplitStr);
        if (MkString::npos == nFind) {
            break;
        }
        strResult = strLeave.substr(0, nFind);
        strLeave = strLeave.substr(nFind + SplitStr.size());
        VesDst.push_back(strResult);
    }
    VesDst.push_back(strLeave);
    return NoneError;
}

Uint32 CMkUtil::BufferSplit(const Uint8* pSrc, Uint32 SrcLen, const Uint8* SplitBuf, Uint32 SplitLen, MkVector<const Uint8*>& VecDst, MkVector<Uint32>& VecLen)
{
    const Uint8* pBegin = pSrc;
    const Uint8* pOffset = pBegin;
    while (pOffset < pSrc + SrcLen - SplitLen) {
        if (0 == memcmp(pOffset, SplitBuf, SplitLen)) {
            if (pOffset != pSrc) {
                VecDst.push_back(pBegin);
                VecLen.push_back(pOffset - pBegin);
                pBegin = pOffset;
            }
            pBegin += SplitLen;
            pOffset += SplitLen;
            continue;
        }
        pOffset++;
    }
    VecDst.push_back(pBegin);
    VecLen.push_back(pSrc + SrcLen - pBegin);
    return NoneError;
}

void CMkUtil::TrimString(MkString& Str)
{
    if (Str.empty()) {
        return;
    }
    size_t nCount = Str.size();
    size_t LeftIndex = 0;
    size_t RightIndex = nCount - 1;
    for (; LeftIndex < nCount; LeftIndex++) {
        if (Str[LeftIndex] > 0x20) {
            break;
        }
    }
    for (; RightIndex > 0; RightIndex--) {
        if (Str[RightIndex] > 0x20) {
            break;
        }
    }
    if (LeftIndex >= RightIndex) {
        Str.clear();
        return;
    }
    Str = Str.substr(LeftIndex, RightIndex + 1 - LeftIndex);
}

Uint32 CMkUtil::SplitPort(const MkString &strPort, MkString &Host, Uint16 &Port)
{
    if (strPort.empty()) {
        MkErrorLog("invalid port:%s\n", strPort.c_str());
        return InvalidParams;
    }
    MkVectorString VecStr;
    StringSplit(strPort, ":", VecStr);
    Host = "0.0.0.0";
    Port = 0;
    if (2 == VecStr.size()) {
        Host = VecStr[0];
        Port = static_cast<Uint16>(std::stoi(VecStr[1]));
    } else if (1 == VecStr.size()) {
        Port = static_cast<Uint16>(std::stoi(VecStr[0]));
    }
    if (0 == Port) {
        MkErrorLog("Port is 0\n");
        return InvalidParams;
    }
    return NoneError;
}

MkString CMkUtil::MyRegexReplace(const MkString &strFrom, const MkString &strRegex, const MkString &Fmt)
{
    MkString StrTo;
    const char *pcRegex = strRegex.c_str();
    for (size_t i = 0; i < strFrom.size(); i++) {
        if (nullptr != strchr(pcRegex, strFrom[i])) { //find
            StrTo += Fmt;
        } else {
            StrTo += MkString(&strFrom[i], 1);
        }
    }
    return StrTo;
}

MkString CMkUtil::SafeMkString(const char *pbuf)
{
    if (pbuf) {
        return MkString(pbuf);
    }
    return "";
}

double CMkUtil::SafeAtof(const char *pbuf)
{
    if (!pbuf) {
        return 0.0;
    }
    return atof(pbuf);
}

Uint32 CMkUtil::SafeAtoi(const char *pbuf)
{
    if (!pbuf) {
        return 0;
    }
    return static_cast<Uint32>(std::atoi(pbuf));
}

Uint32 CMkUtil::SafeAtoi(const MkString& StrBuf)
{
    Uint32 nRet = 0;
    try {
        nRet = std::stoi(StrBuf);
    } catch (const std::exception &e) {
        MkDebugLog("safe atoi error:%s\n", e.what());
    }
    return nRet;
}

Uint32 CMkUtil::RtspUrlParse(const MkString &RtspUrl, MkString &Host, Uint16 &Port)
{
    if ("rtsp://" != RtspUrl.substr(0, 7)) {
        return InvalidUrl;
    }
    MkString Tmp = RtspUrl.substr(7);
    size_t npos = Tmp.find("@");
    if (MkString::npos != npos) {
        Tmp = Tmp.substr(npos + 1);
    }
    size_t nfind = Tmp.find(":");
    size_t nfind1 = Tmp.find("/");
    if (MkString::npos == nfind || nfind > nfind1) { //not find :
        Port = 554;
        Host = Tmp.substr(0, nfind1);
    } else {
        Host = Tmp.substr(0, nfind);
        MkString strPort = Tmp.substr(nfind + 1, nfind1 - nfind);
        Port = static_cast<Uint16>(std::stoi(strPort));
    }
    return NoneError;
}

Uint32 CMkUtil::RtmpUrlParse(const MkString &RtspUrl, MkString &Host, Uint16 &Port)
{
    if ("rtmp://" != RtspUrl.substr(0, 7)) {
        return InvalidUrl;
    }
    MkString Tmp = RtspUrl.substr(7);
    size_t nfind = Tmp.find(":");
    size_t nfind1 = Tmp.find("/");
    if (MkString::npos == nfind || nfind > nfind1) { //not find :
        Port = 1935;
        Host = Tmp.substr(0, nfind1);
    } else {
        Host = Tmp.substr(0, nfind);
        MkString strPort = Tmp.substr(nfind + 1, nfind1 - nfind);
        Port = static_cast<Uint16>(std::stoi(strPort));
    }
    return NoneError;
}

Uint32 CMkUtil::HttpUrlParse(const MkString &HttpUrl, MkString &Host, Uint16 &Port, MkString& Path)
{
    Uint32 ErrorCode = NoneError;
    if ("http://" == HttpUrl.substr(0, 7)) {
        MkString Tmp = HttpUrl.substr(7);
        size_t nfind = Tmp.find(":");
        size_t nfind1 = Tmp.find("/");
        if (MkString::npos == nfind || nfind > nfind1) { //not find :
            Port = 80;
            Host = Tmp.substr(0, nfind1);
        } else {
            Host = Tmp.substr(0, nfind);
            MkString strPort = Tmp.substr(nfind + 1, nfind1 - nfind - 1);
            Port = static_cast<Uint16>(std::stoi(strPort));
        }
        Path = Tmp.substr(nfind1);
        ErrorCode = NoneError;
    } else if ("https://" == HttpUrl.substr(0, 8)) {
        MkString Tmp = HttpUrl.substr(8);
        size_t nfind = Tmp.find(":");
        size_t nfind1 = Tmp.find("/");
        if (MkString::npos == nfind) { //not find :
            Port = 443;
            Host = Tmp.substr(0, nfind1);
        } else {
            Host = Tmp.substr(0, nfind);
            MkString strPort = Tmp.substr(nfind + 1, nfind1 - nfind - 1);
            Port = static_cast<Uint16>(std::stoi(strPort));
        }
        Path = Tmp.substr(nfind1);
        ErrorCode = NoneError;
    } else {
        ErrorCode = InvalidUrl;
    }

    return ErrorCode;
}

Uint32 CMkUtil::GetLocalIp(MkString& LocalIp)
{
    Uint32 ErrorCode = UnknownError;
#ifdef _WIN32
    char szText[256];
    int iRet = gethostname(szText, 256);
    if (iRet) {
        return SystemError;
    }
    struct addrinfo  hints, *res;
    memset(&hints, 0, sizeof(addrinfo));
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_family = AF_INET;
    int hosttem = getaddrinfo(szText, "", &hints, &res);
    if (hosttem) {
        return SystemError;
    }

    in_addr local_ip;
    local_ip.S_un.S_addr = ((sockaddr_in*)(res->ai_addr))->sin_addr.s_addr;

    char str[256];
    inet_ntop(AF_INET, &(local_ip.S_un.S_addr), str, 256);
    LocalIp = str;
    ErrorCode = NoneError;
#else
    int i = 0;
    int sockfd;
    struct ifconf ifconf;
    char buf[512];
    struct ifreq *ifreq;
    ifconf.ifc_len = 512;
    ifconf.ifc_buf = buf;
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        return SocketCreateFailed;
    }
    ioctl(sockfd, SIOCGIFCONF, &ifconf);
    ifreq = (struct ifreq*)buf;
    for (i = (ifconf.ifc_len / sizeof(struct ifreq)); i > 0; i--) {
        LocalIp = inet_ntoa(((struct sockaddr_in*)&(ifreq->ifr_addr))->sin_addr);
        if ("127.0.0.1" != LocalIp) {
            ErrorCode = NoneError;
            break;
        }
        ifreq++;
    }
#endif
    return ErrorCode;
}

BOOL CMkUtil::IsLanIp(const MkString& Ip)
{
    /*
    A类地址：10.0.0.0--10.255.255.255
    B类地址：172.16.0.0--172.31.255.255
    C类地址：192.168.0.0--192.168.255.255
    */
    Uint32 uIp = inet_addr(Ip.c_str());

    return  (0x0a == (uIp & 0xFF)) || ((0xAC == (uIp & 0xFF)) && 0x10 <= ((uIp >> 8) & 0xFF) && ((uIp >> 8) & 0xFF) <= 0x1F) || (0xA8C0 == (uIp & 0xFFFF));
}

Uint32 CMkUtil::StringToAscii(const MkString& strInput, MkString& strOutput)
{
    const char* pbuf = strInput.c_str();
    size_t nlen = strInput.size();
    for (size_t i = 0; i < nlen; i++) {
        if (pbuf[i] < '\''
            || pbuf[i]>'~') {
            strOutput += "%";
            strOutput += pHex[(Uint8)pbuf[i] >> 4];
            strOutput += pHex[(Uint8)pbuf[i] & 0x0f];
        } else {
            strOutput += pbuf[i];
        }
    }
    return NoneError;
}

BOOL CMkUtil::IsHex(Uint8 Value)
{
    for (int i = 0; i < Len16; i++) {
        if (Value == pHex[i]) {
            return TRUE;
        }
    }
    return FALSE;
}

Uint32 CMkUtil::BufferReadLine(const MkString& Content, INOUT Uint32 &nPos, OUT MkString& StrLine)
{
    Uint32 ExtraDrain = 0;
    size_t NewPos = Content.find("\n", nPos);
    if (MkString::npos == NewPos) {
        return InvalidParams;
    }
    NewPos += 1;
    MkString strTmp = Content.substr(nPos, NewPos - nPos);
    ExtraDrain = 1;
    if (MkString::npos != strTmp.find("\r")) {
        ExtraDrain++;
    }
    StrLine = Content.substr(nPos, NewPos - nPos - ExtraDrain);
    nPos = NewPos;
    return NoneError;
}

Uint32 CMkUtil::ReadLine(const Int8* Content, Uint32 nLen, INOUT Uint32 &nPos, OUT MkString& strLine)
{
    const Int8* pFind = strstr(Content + nPos, "\r\n");
    if (nullptr != pFind && pFind < Content + nPos + nLen) {
        strLine = MkString(Content + nPos, pFind - Content - nPos);
        nPos = pFind - Content + 2;
        return NoneError;
    }
    pFind = strstr(Content, "\n");
    if (nullptr != pFind && pFind < Content + nPos + nLen) {
        strLine = MkString(Content + nPos, pFind - Content - nPos);
        nPos = pFind - Content + 1;
        return NoneError;
    }
    return NotHasEnoughBuffer;
}

#ifdef _WIN32
#include <assert.h>
#include <codecvt>
using WCHAR_GBK = std::codecvt_byname<wchar_t, char, mbstate_t>;
using WCHAR_UTF8 = std::codecvt_utf8<wchar_t>;
#define GBK_NAME ".936"
Uint32 CMkUtil::Gbk2Utf8(const MkString &strGbk, MkString &strUtf8)
{
    try {
        std::wstring_convert<WCHAR_GBK>  cvtGBK(new WCHAR_GBK(GBK_NAME));
        std::wstring_convert<WCHAR_UTF8> cvtUTF8;
        std::wstring ustr = cvtGBK.from_bytes(strGbk);
        strUtf8 = cvtUTF8.to_bytes(ustr);
    } catch (const std::exception &e) {
        MkDebugLog("error:%s\n", e.what());
        strUtf8 = strGbk;
    }
    return NoneError;
}

Uint32 CMkUtil::Utf8ToGbk(const MkString &strUtf8, MkString &strGbk)
{
    try {
        std::wstring_convert<WCHAR_GBK>  cvtGBK(new WCHAR_GBK(GBK_NAME));
        std::wstring_convert<WCHAR_UTF8> cvtUTF8;
        std::wstring ustr = cvtUTF8.from_bytes(strUtf8);
        strGbk = cvtGBK.to_bytes(ustr);
    } catch (const std::exception &e) {
        MkDebugLog("error:%s\n", e.what());
        strGbk = strUtf8;
    }
    return NoneError;
}
#else
Uint32 CodeConvert(const Int8 *FromCharSet, const Int8 *ToCharSet, Int8 *pInBuf, size_t InLen,
    Int8 *pOutBuf, size_t OutLen)
{
    iconv_t cd;
    Int8 **ppIn = &pInBuf;
    Int8 **ppOut = &pOutBuf;

    cd = iconv_open(ToCharSet, FromCharSet);
    if (cd == 0) {

        return SystemError;
    }

    memset(pOutBuf, 0, OutLen);

    if ((int)iconv(cd, ppIn, &InLen, ppOut, &OutLen) == -1) {
        iconv_close(cd);
        return SystemError;
    }
    iconv_close(cd);

    return NoneError;
}

Uint32 CMkUtil::Gbk2Utf8(const MkString &strGbk, MkString &strUtf8)
{
    //if (!IsGbkString(strGbk)) {
    //    MkWarningLog("buffer:%s is utf8 copy it\n", strGbk.c_str());
    //    strUtf8 = strGbk;
    //    return NoneError;
    //}
    size_t Length = strGbk.size();
    char *pbuf = (char*)malloc(Length * 2 + 1);
    memset(pbuf, 0, Length * 2 + 1);
    Uint32 ErrorCode = CodeConvert("gb2312", "utf-8", (char*)strGbk.c_str(), strGbk.size(), pbuf, Length * 2);
    strUtf8 = pbuf;
    free(pbuf);
    return ErrorCode;
}

Uint32 CMkUtil::Utf8ToGbk(const MkString &strUtf8, MkString &strGbk)
{
    //if (!IsUtf8String(strUtf8)) {
    //    MkWarningLog("str:%s is gbk copy it\n", strUtf8.c_str());
    //    strGbk = strUtf8;
    //    return NoneError;
    //}
    size_t Length = strlen(strUtf8.c_str());
    char *pbuf = (char*)malloc(Length * 2 + 1);
    memset(pbuf, 0, Length * 2 + 1);
    Uint32 ErrorCode = CodeConvert("utf-8", "gb2312", (char*)strUtf8.c_str(), Length, pbuf, Length * 2);
    strGbk = pbuf;
    free(pbuf);
    return ErrorCode;
}
#endif

Uint32 CMkUtil::GetOneIpByHostName(const MkString& HostName, MkString& IpAddr)
{
    Uint32 ErrorCode = NoneError;
    struct hostent* pHostEntry = gethostbyname(HostName.c_str());
    if (NULL != pHostEntry) {
        char** pptr = NULL;
        char szIpBuff[32] = { 0 };
        for (pptr = pHostEntry->h_addr_list; *pptr != NULL; ++pptr) {
            memset(szIpBuff, 0, sizeof(szIpBuff));
            inet_ntop(pHostEntry->h_addrtype, *pptr, szIpBuff, sizeof(szIpBuff));
            IpAddr = szIpBuff;
            break;
        }
    } else {
        ErrorCode = InvalidParams;
    }
    return ErrorCode;
}

Uint32 CMkUtil::ReadTextProtocolHead(const Int8* Content, Uint32 nLen, Uint32& nUsed)
{
    const Int8* pFind = strstr(Content, "\n\r\n");
    if (nullptr != pFind && pFind < Content + nLen) {
        nUsed = pFind - Content + 3;
        return NoneError;
    }
    pFind = strstr(Content, "\n\n");
    if (nullptr != pFind && pFind < Content + nLen) {
        nUsed = pFind - Content + 2;
        return NoneError;
    }
    return InvalidParams;
}

BOOL CMkUtil::EndByString(const MkString& Content, const MkString& strEnd)
{
    if (Content.size() < strEnd.size()) {
        return FALSE;
    }
    return strEnd == Content.substr(Content.size() - strEnd.size());
}

BOOL CMkUtil::BeginByString(const MkString& Content, const MkString& strBegin)
{
    if (Content.size() < strBegin.size()) {
        return FALSE;
    }
    return strBegin == Content.substr(0, strBegin.size());
}